/*
 * FileName：SysMenuServiceImpl.java 
 * <p>
 * Copyright (c) 2017-2020 <a href="https://www.smartwx.info">hermit(1154808491@qq.com)</a>.
 * <p>
 * Licensed under the GNU General Public License, Version 3 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/gpl-3.0.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package com.smart.sys.service.impl;

import javax.annotation.Resource;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.smart.common.Constants;
import com.smart.common.entity.TreeNode;
import com.smart.common.util.SessionUtil;
import com.smart.common.util.StringUtil;
import com.smart.common.util.Util;
import com.smart.sys.entity.SysUserRole;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import com.smart.sys.dao.SysMenuMapper;
import com.smart.sys.entity.SysMenu;
import com.smart.sys.service.ISysMenuService;

/**
 * 资源菜单信息
 *
 * @author hermit
 * @version 2.0
 * @date 2018-12-30 22:26:32
 */
@Service
@Transactional
public class SysMenuServiceImpl implements ISysMenuService {

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Override
    public SysMenu queryObject(SysMenu sysMenu) throws Exception {
        return sysMenuMapper.queryObject(sysMenu);
    }

    @Override
    public List<SysMenu> queryList(SysMenu sysMenu) throws Exception {
        return sysMenuMapper.queryList(sysMenu);
    }

    @Override
    public List<SysMenu> queryListByPage(SysMenu sysMenu) throws Exception {
        return sysMenuMapper.queryListByPage(sysMenu);
    }

    @Override
    public Integer queryCount(SysMenu sysMenu) throws Exception {
        Integer ct = sysMenuMapper.queryCount(sysMenu);
        return ct == null ? 0 : ct;
    }

    @Override
    public Integer insert(SysMenu sysMenu) throws Exception {
        sysMenu.setMenuId(Util.getUUID());
        sysMenu.setCreateTime(new Date());
        sysMenu.setUpdateTime(new Date());
        sysMenu.setCreateUser(SessionUtil.getUserId());
        sysMenu.setUpdateUser(SessionUtil.getUserId());
        sysMenu.setExpandFlag(Constants.EXPAND_NO);
        sysMenu.setLeafFlag(Constants.LEAF_YES);
        sysMenu.setSystemFlag(Constants.SYSTEM_FLAG_NO);
        sysMenu.setIframeFlag(Constants.IFRAME_NO);
        //父节点修改叶子节点
        sysMenuMapper.update(SysMenu.builder().menuId(sysMenu.getParentId()).leafFlag(Constants.LEAF_NO).build());
        return sysMenuMapper.insert(sysMenu);
    }

    @Override
    public Integer update(SysMenu sysMenu) throws Exception {
        sysMenu.setUpdateTime(new Date());
        sysMenu.setUpdateUser(SessionUtil.getUserId());
        return sysMenuMapper.update(sysMenu);
    }

    @Override
    public Integer delete(SysMenu sysMenu) throws Exception {
        sysMenuMapper.delete(sysMenu);
        //更新父节点
        Integer count = sysMenuMapper.queryCount(SysMenu.builder().parentId(sysMenu.getParentId()).build());
        if (count == 0) {
            sysMenuMapper.update(SysMenu.builder().menuId(sysMenu.getParentId()).leafFlag(Constants.LEAF_YES).build());
        }
        return 1;
    }

    @Override
    public Integer deleteBatch(List<String> menuIds) throws Exception {
        return sysMenuMapper.deleteBatch(menuIds);
    }

    @Override
    public List<SysMenu> getMenuList(SysUserRole sysUserRole) {
        List<SysMenu> menuList = sysMenuMapper.getMenuList(sysUserRole);
        if (CollectionUtils.isNotEmpty(menuList)) {
            //进行数据组装
            menuList = buildListToTree(menuList);
        }
        return menuList;
    }

    @Override
    public List<TreeNode> tree(SysUserRole sysUserRole) throws Exception {
        //查询所有的菜单
        List<SysMenu> sysMenus = sysMenuMapper.queryList(SysMenu.builder().build());
        //进行组装treenode
        List<TreeNode> treeNodes = sysMenus.parallelStream().map(menu -> TreeNode.builder()
                .id(menu.getMenuId())
                .name(menu.getMenuName())
                .attrs(ImmutableMap.of("systemFlag", menu.getSystemFlag()))
                .isParent(Constants.LEAF_NO.equals(menu.getLeafFlag()))
                .parentId(menu.getParentId()).build()).collect(Collectors.toList());
        if (null != sysUserRole && StringUtil.isNotBlank(sysUserRole.getRoleId())) {
            //查询角色下的菜单
            List<SysMenu> roleMenus = sysMenuMapper.getMenuList(sysUserRole);
            //选中处理
            if (CollectionUtils.isNotEmpty(roleMenus)) {
                treeNodes.forEach(treeNode -> treeNode.setChecked(roleMenus.parallelStream().anyMatch(sysMenu -> sysMenu.getMenuId().equals(treeNode.getId()))));
            }
        }

        return treeNodes;
    }

    /**
     * 进行数据组装
     *
     * @param menus
     * @return
     */
    private List<SysMenu> buildListToTree(List<SysMenu> menus) {
        //取得root根目录
        SysMenu rootMenu = menus.parallelStream().filter(sysMenu -> Constants.ROOT_NODE_PARENT_ID.equals(sysMenu.getParentId())).collect(Collectors.toList()).get(0);
        rootMenu.setSubList(findSubList(rootMenu, menus));
        return rootMenu.getSubList();
    }

    /**
     * 递归调用
     *
     * @param root
     * @param allSysMenus
     * @return
     */
    private List<SysMenu> findSubList(SysMenu root, List<SysMenu> allSysMenus) {
        List<SysMenu> subList = allSysMenus.parallelStream().filter(sysMenu -> sysMenu.getParentId().equals(root.getMenuId())).collect(Collectors.toList());
        List<SysMenu> notChildren = (List<SysMenu>) CollectionUtils.subtract(allSysMenus, subList);
        subList.forEach(sysMenu ->
        {
            List<SysMenu> tmpSubList = findSubList(sysMenu, notChildren);
            sysMenu.setSubList(tmpSubList);
        });
        return subList;
    }
}
